/**
 * Create in 2012-3-3.
 */
package com.surekam.mnai.service.extractor.parser;

import java.io.InputStream;
import java.util.Date;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.surekam.mnai.model.Address;
import com.surekam.mnai.model.MobileNumberAttribution;
import com.surekam.mnai.util.ObjectUtil;
import com.surekam.mnai.util.StringUtil;

/**
 * 一个通用的Xml文档类型的结果的解析器。
 * 
 * @author 吴政
 * 
 */
public class XmlParser implements IMobileNumberAttributionParser {

	/**
	 * Xml文档中手机号码段节点的XPath。
	 */
	protected String mobileNumberSegmentNodeXPath;

	/**
	 * Xml文档中手机卡类型节点的XPath。
	 */
	protected String phoneCardTypeNodeXPath;

	/**
	 * Xml文档中手机号码所属省份节点的XPath。
	 */
	protected String provinceNodeXPath;

	/**
	 * Xml文档中手机号码所属城市节点的XPath。
	 */
	protected String cityNodeXPath;

	/**
	 * Xml文档中手机号码归属地区号节点的XPath。
	 */
	protected String areaCodeNodeXPath;

	/**
	 * Xml文档中手机号码归属地邮政编码节点的XPath。
	 */
	protected String postCodeNodeXPath;

	/**
	 * 从输入流中解析获得的Xml文档。
	 */
	protected Document xmlDocument;

	/**
	 * @see com.surekam.mnai.service.extractor.parser.IMobileNumberAttributionParser#parse(java.io.InputStream)
	 */
	@Override
	public MobileNumberAttribution parse(InputStream is)
			throws ParseFailedException {
		readDocument(is);

		return createMobileNumberAttribution();
	}

	/**
	 * 从输入流中读取Xml文档。
	 * 
	 * @param is
	 *            输入流
	 * @throws ParseFailedException
	 *             如果读取失败，则抛出此异常。
	 */
	protected void readDocument(InputStream is) throws ParseFailedException {
		SAXReader reader = new SAXReader();

		try {
			xmlDocument = reader.read(is);
		} catch (DocumentException e) {
			throw new ParseFailedException(e);
		}
	}

	/**
	 * 从Xml文档中读取信息创建MobileNumberAttribution对象。
	 * 
	 * @return MobileNumberAttribution对象
	 * @throws ParseFailedException
	 *             如果读取信息或创建对象失败，则抛出此异常。
	 */
	protected MobileNumberAttribution createMobileNumberAttribution()
			throws ParseFailedException {
		String mobileNumberSegment = getMobileNumberSegment();
		String phoneCardType = getPhoneCardType();
		Address address = getAddress();

		return new MobileNumberAttribution(mobileNumberSegment, phoneCardType,
				address, new Date());
	}

	/**
	 * 从Xml文档中读取信息创建Address对象。
	 * 
	 * @return Address对象
	 * @throws ParseFailedException
	 *             如果读取信息或创建对象失败，则抛出此异常。
	 */
	protected Address getAddress() throws ParseFailedException {
		String province = getProvince();
		String city = getCity();
		String areaCode = getAraeCode();
		String postcode = getPostCode();

		if (ObjectUtil.String.isAllNotEmpty(province, city)) {
			return createAddressByProvinceAndCity(province, city);
		} else if (ObjectUtil.String.isAllNotEmpty(areaCode)) {
			return createAddressByAreaCode(areaCode);
		} else if (ObjectUtil.String.isAllNotEmpty(postcode)) {
			return createAddressByPostcode(postcode);
		} else {
			throw new ParseFailedException(
					"The result infomation is too lack to create address object.");
		}
	}

	/**
	 * 返回手机号码段的解析结果。
	 * 
	 * @return 手机号码段
	 */
	protected String getMobileNumberSegment() {
		return getStringValueByXPath(mobileNumberSegmentNodeXPath).substring(0,
				7);
	}

	/**
	 * 返回手机卡类型的解析结果。
	 * 
	 * @return 手机卡类型
	 */
	protected String getPhoneCardType() {
		return getStringValueByXPath(phoneCardTypeNodeXPath);
	}

	/**
	 * 返回手机号码所属省份的解析结果。
	 * 
	 * @return 所属省份
	 */
	protected String getProvince() {
		String province = getStringValueByXPath(provinceNodeXPath);
		
		return ObjectUtil.String.eraseEndsWith(province, "省");
	}

	/**
	 * 返回手机号码所属城市的解析结果。
	 * 
	 * @return 所属城市
	 */
	protected String getCity() {
		String city = getStringValueByXPath(cityNodeXPath);
		
		return ObjectUtil.String.eraseEndsWith(city, "市");
	}

	/**
	 * 返回手机号码所属地区号的解析结果。
	 * 
	 * @return 区号
	 */
	protected String getAraeCode() {
		return getStringValueByXPath(areaCodeNodeXPath);
	}

	/**
	 * 返回手机号码所属地邮政编码的解析结果。
	 * 
	 * @return 邮政编码
	 */
	protected String getPostCode() {
		return getStringValueByXPath(postCodeNodeXPath);
	}

	/**
	 * 根据号码所属省份和城市创建一个Address对象。
	 * 
	 * @param province
	 *            所属省份
	 * @param city
	 *            所属城市
	 * @return Address对象
	 */
	protected Address createAddressByProvinceAndCity(String province,
			String city) {
		return new Address(0, province, city, "", "");
	}

	/**
	 * 根据号码所属地区号创建一个Address对象。
	 * 
	 * @param areaCode
	 *            区号
	 * @return Address对象
	 */
	protected Address createAddressByAreaCode(String areaCode) {
		return new Address(0, "", "", areaCode, "");
	}

	/**
	 * 根据号码所属地邮政编码创建一个Address对象。
	 * 
	 * @param postcode
	 *            邮政编码
	 * @return Address对象
	 */
	protected Address createAddressByPostcode(String postcode) {
		return new Address(0, "", "", "", postcode);
	}

	/**
	 * 获取指定XPath指向的节点的字符串类型值，如果XPath为空或节点的值为空，则返回一个空字符串。
	 * 
	 * @param xPath
	 *            节点的XPath
	 * @return 节点的字符串类型值
	 */
	protected String getStringValueByXPath(String xPath) {
		if (!StringUtil.isEmpty(xPath)) {
			Node node = xmlDocument.selectSingleNode(xPath);

			if (node != null) {
				String value = node.getStringValue();

				if (!StringUtil.isEmpty(value)) {
					return value;
				}
			}
		}

		return "";
	}

	public String getMobileNumberSegmentNodeXPath() {
		return mobileNumberSegmentNodeXPath;
	}

	/**
	 * 设置Xml文档中手机号码段节点的XPath。
	 * 
	 * @param mobileNumberSegmentNodeXPath
	 *            Xml文档中手机号码段节点的XPath
	 */
	public void setMobileNumberSegmentNodeXPath(
			String mobileNumberSegmentNodeXPath) {
		this.mobileNumberSegmentNodeXPath = mobileNumberSegmentNodeXPath;
	}

	public String getPhoneCardTypeNodeXPath() {
		return phoneCardTypeNodeXPath;
	}

	/**
	 * 设置Xml文档中手机号码段节点的XPath。
	 * 
	 * @param mobileNumberSegmentNodeXPath
	 *            Xml文档中手机号码段节点的XPath
	 */
	public void setPhoneCardTypeNodeXPath(String phoneCardTypeNodeXPath) {
		this.phoneCardTypeNodeXPath = phoneCardTypeNodeXPath;
	}

	public String getProvinceNodeXPath() {
		return provinceNodeXPath;
	}

	/**
	 * 设置Xml文档中手机号码段所属省份节点的XPath。
	 * 
	 * @param mobileNumberSegmentNodeXPath
	 *            Xml文档中手机号码段所属省份节点的XPath
	 */
	public void setProvinceNodeXPath(String provinceNodeXPath) {
		this.provinceNodeXPath = provinceNodeXPath;
	}

	public String getCityNodeXPath() {
		return cityNodeXPath;
	}

	/**
	 * 设置Xml文档中手机号码段所属城市节点的XPath。
	 * 
	 * @param mobileNumberSegmentNodeXPath
	 *            Xml文档中手机号码段所属城市节点的XPath
	 */
	public void setCityNodeXPath(String cityNodeXPath) {
		this.cityNodeXPath = cityNodeXPath;
	}

	public String getAreaCodeNodeXPath() {
		return areaCodeNodeXPath;
	}

	/**
	 * 设置Xml文档中手机号码段所属地区号节点的XPath。
	 * 
	 * @param mobileNumberSegmentNodeXPath
	 *            Xml文档中手机号码段所属地区号节点的XPath
	 */
	public void setAreaCodeNodeXPath(String areaCodeNodeXPath) {
		this.areaCodeNodeXPath = areaCodeNodeXPath;
	}

	public String getPostCodeNodeXPath() {
		return postCodeNodeXPath;
	}

	/**
	 * 设置Xml文档中手机号码段所属地邮政编码节点的XPath。
	 * 
	 * @param mobileNumberSegmentNodeXPath
	 *            Xml文档中手机号码段所属地邮政编码节点的XPath
	 */
	public void setPostCodeNodeXPath(String postCodeNodeXPath) {
		this.postCodeNodeXPath = postCodeNodeXPath;
	}

}
